﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using CMS.Entities;
using CMS.Extensions;
using CMS.Managers;
using CMS.Resources;
using DataBaseLayer.Dto;
using GrigSoft.Managers.Abstractions.Interfaces.Drawing;
using GrigSoft.Managers.Abstractions.Interfaces.IO;
using GrigSoft.Managers.Drawing;
using GrigSoft.Managers.IO;
using GrigSoft.Managers.Net;

namespace CMS.Forms
{
	public partial class frmAdminControlPanel : Form
	{
		#region Variables

		private int? _id;
		private int? _subItemId;
		private bool _isInicializeCheckBox;
		private readonly IFileManager _fileManager;
		private readonly IDirectoryManager _directoryManager;
		private readonly IImageManager _imageManager;

		private readonly GalleryManager _galleryManager;

		#endregion

		#region Constructors

		public frmAdminControlPanel()
		{
			InitializeComponent();

			var ftpManagerForSmallImages = new FTPManager(AppConfig.FtpHostNameSmallImages, AppConfig.FtpUserName, AppConfig.FtpPassword);
			var ftpManagerForBigImages = new FTPManager(AppConfig.FtpHostNameBigImages, AppConfig.FtpUserName, AppConfig.FtpPassword);

			_fileManager = new FileManager();
			_directoryManager = new DirectoryManager();
			_imageManager = new ImageManager();

			_galleryManager = new GalleryManager(_directoryManager, _fileManager, ftpManagerForBigImages, ftpManagerForSmallImages);

			tcControlPanel.SelectedIndexChanged += tcControlPanel_SelectedIndexChanged;
			tcControlPanel.SelectedTab = tpNews;
			tpNewsInicialize();
		}

		#endregion

		void tcControlPanel_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.Enabled = false;

			var tabControl = (sender as TabControl);
			if (tabControl != null)
			{
				switch (tabControl.SelectedTab.Text)
				{
					case "Новости":
						tpNewsInicialize();
						break;

					case "Галереи":
						tpGalleriesInicialize();
						break;

					case "Расписание Богослужений":
						tpScheduleInicialize();
						break;

					case "Обработка Изображений Для Галерей":
						tpImagesManagerInicialize();
						break;

					default:
						break;
				}
			}

			this.Enabled = true;
		}

		#region Internal Implementation

		private void tpNewsInicialize()
		{
			pEditNews.Visible = false;

			cbNews.Clear();
			cbNews.DataSource = AppContext.ServiceFactory.NewsService.GetNews();
			cbNews.DisplayMember = "Header";
			cbNews.ValueMember = "NewsId";
		}

		private void tpScheduleInicialize()
		{
			dtpSheduleStart.Value = AppContext.ServiceFactory.ScheduleService.GetScheduleStartDate();

			pSheduleService.Visible = false;
			pSheduleDay.Visible = false;

			cbSheduleDays.Clear();
			cbSheduleDays.DataSource = AppContext.ServiceFactory.ScheduleService.GetDays();
			cbSheduleDays.DisplayMember = "Day";
			cbSheduleDays.ValueMember = "DayId";
		}

		private void pScheduleDayInicialize()
		{
			pSheduleDay.Visible = true;
			pSheduleService.Visible = false;

			cbSheduleServices.Clear();
			cbSheduleServices.DataSource =
				AppContext.ServiceFactory.ScheduleService.GetDayServicesByDayId(_id.GetValueOrDefault());
			cbSheduleServices.DisplayMember = "Name";
			cbSheduleServices.ValueMember = "ServiceId";
		}

		private void tpGalleriesInicialize()
		{
			pEditGallery.Visible = false;
			pGalleryImages.Visible = false;
			pEditGalleryImage.Visible = false;

			chbImageGalleries.Checked = true;
			chbFotoclubGalleries.Checked = false;

			ComboBoxGalleriesInicialize();
		}

		private void tpImagesManagerInicialize()
		{
			pManagedImagesData.Visible = true;
			pManagedImagesProgress.Visible = false;

			txtResultImagesFolder.Text
				= txtFolderPathWithImages.Text
				= string.Empty;
		}

		private void ComboBoxGalleriesInicialize()
		{
			var galleries = new List<GalleryData>();

			if (chbFotoclubGalleries.Checked)
				galleries.AddRange(AppContext.ServiceFactory.GalleriesService.GetFotoclubGalleries());
			if (chbImageGalleries.Checked)
				galleries.AddRange(AppContext.ServiceFactory.GalleriesService.GetImageGalleries());

			cbGalleries.Clear();
			cbGalleries.DataSource = galleries;
			cbGalleries.DisplayMember = "Name";
		}

		private void ComboBoxGalleryImagesInicialize(int galleryId)
		{
			cbGalleryImages.Clear();
			var images = AppContext.ServiceFactory.GalleriesService.GetGalleryImagesByGalleryId(galleryId);
			cbGalleryImages.DataSource = images;
			cbGalleryImages.DisplayMember = "Url";
		}

		private void InicializeProgressBar(ProgressBar progressBar, int countOperations)
		{
			if (progressBar == null || countOperations <= 0) return;

			progressBar.Visible = true;
			progressBar.Minimum = 1;
			progressBar.Maximum = countOperations;
			progressBar.Value = 1;
			progressBar.Step = 1;
		}

		private IEnumerable<string> SortFilePathes(IEnumerable<string> data)
		{
			if (data == null) return null;

			return data.OrderBy(i =>
			{
				int number;
				var fileName = new FileInfo(i).Name;
				int.TryParse(
					fileName.Contains(".")
						? fileName.Substring(0, fileName.IndexOf(".", StringComparison.Ordinal))
						: fileName, out number);
				return number;
			}).ToList();
		}

		#endregion

		#region Tab News Actions

		private void btnEditNews_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var news = (cbNews.SelectedItem as NewsData);

			if (news != null)
			{
				_id = news.NewsId;

				txtHeader.Text = news.Header;
				txtDescription.Text = news.Description;

				pEditNews.Visible = true;

				cbNewsGalleries.Clear();
				cbNewsGalleries.DataSource = AppContext.ServiceFactory.GalleriesService.GetGalleries();
				cbNewsGalleries.DisplayMember = "Name";
				cbNewsGalleries.ValueMember = "GalleryId";
			}

			this.Enabled = true;
		}

		private void btnAddNews_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			pEditNews.Visible = true;

			_id = null;

			txtHeader.Text = string.Empty;
			txtDescription.Text = string.Empty;

			cbNewsGalleries.Clear();
			cbNewsGalleries.DataSource = AppContext.ServiceFactory.GalleriesService.GetGalleries();
			cbNewsGalleries.DisplayMember = "Name";
			cbNewsGalleries.ValueMember = "GalleryId";

			this.Enabled = true;
		}

		private void btnSaveNews_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			if (!string.IsNullOrWhiteSpace(txtHeader.Text) && !string.IsNullOrWhiteSpace(txtDescription.Text))
			{
				var gallery = (cbNewsGalleries.SelectedItem as GalleryData);
				var news = new NewsData
				{
					Description = txtDescription.Text,
					Header = txtHeader.Text,
					GalleryId = gallery != null ? gallery.GalleryId : 0
				};

				if (_id.HasValue)
				{
					news.NewsId = _id.GetValueOrDefault();
					AppContext.ServiceFactory.NewsService.UpdateNews(news);
				}
				else
					AppContext.ServiceFactory.NewsService.CreateNews(news);

				_id = null;
				pEditNews.Visible = false;
				tpNewsInicialize();
			}
			else
				MessageBox.Show(string.Format("Поля 'Название новости' и 'Текст новости' обязательны для заполнения"));

			this.Enabled = true;
		}

		private void btnDeleteNews_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var news = (cbNews.SelectedItem as NewsData);

			if (news != null)
			{
				AppContext.ServiceFactory.NewsService.DeleteNewsById(news.NewsId);

				pEditNews.Visible = false;
				tpNewsInicialize();
			}

			this.Enabled = true;
		}

		#endregion

		#region Tab Shedule Actions

		private void btnSheduleStart_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			AppContext.ServiceFactory.ScheduleService.UpdateScheduleDates(dtpSheduleStart.Value);

			this.Enabled = true;
			MessageBox.Show(string.Format("Дата понедельника успешно установлена"));
		}

		private void btnSheduleEdit_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var day = (cbSheduleDays.SelectedItem as ScheduleDayData);

			if (day != null)
			{
				_id = day.DayId;
				lblSheduleSelectedDayName.Text = day.Day;
				chbSheduleDay.Checked = day.IsSpecialDay;

				pScheduleDayInicialize();
			}

			this.Enabled = true;
		}

		private void chbSheduleDay_CheckedChanged(object sender, EventArgs e)
		{
			this.Enabled = false;

			AppContext.ServiceFactory.ScheduleService.UpdateIsSpecialDayParameterByDayId(_id.GetValueOrDefault(), chbSheduleDay.Checked);

			this.Enabled = true;
		}

		private void btnSheduleServiceEdit_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var scheduleService = (cbSheduleServices.SelectedItem as ScheduleServiceData);

			if (scheduleService != null)
			{
				_subItemId = scheduleService.ServiceId;

				txtSheduleServiceName.Text = scheduleService.Name;
				txtSheduleServiceHH.Text = scheduleService.Time.Hours.ToString(CultureInfo.InvariantCulture);
				txtSheduleServiceMM.Text = scheduleService.Time.Minutes.ToString(CultureInfo.InvariantCulture);

				pSheduleService.Visible = true;
			}

			this.Enabled = true;
		}

		private void btnSheduleServiceAdd_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			_subItemId = null;

			txtSheduleServiceName.Text = txtSheduleServiceHH.Text = txtSheduleServiceMM.Text = string.Empty;

			pSheduleService.Visible = true;

			this.Enabled = true;
		}

		private void btnSheduleServiceDelete_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var scheduleService = (cbSheduleServices.SelectedItem as ScheduleServiceData);

			if (scheduleService != null)
			{
				AppContext.ServiceFactory.ScheduleService.DeleteScheduleServiceById(scheduleService.ServiceId);
				pScheduleDayInicialize();
			}

			this.Enabled = true;
		}

		private void btnSheduleServiceSave_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			int timeHH;
			var isHH = int.TryParse(txtSheduleServiceHH.Text, out timeHH) && timeHH >= 0 && timeHH <= 24;

			int timeMM;
			var isMM = int.TryParse(txtSheduleServiceMM.Text, out timeMM) && timeMM >= 0 && timeMM <= 59;

			if (!string.IsNullOrWhiteSpace(txtSheduleServiceName.Text) && isHH && isMM)
			{
				var scheduleService = new ScheduleServiceData
				{
					DayId = _id.GetValueOrDefault(),
					Name = txtSheduleServiceName.Text,
					ServiceId = _subItemId.GetValueOrDefault(),
					Time = new TimeSpan(timeHH, timeMM, 0)
				};

				if (_subItemId.HasValue)
					AppContext.ServiceFactory.ScheduleService.UpdateScheduleService(scheduleService);
				else
					AppContext.ServiceFactory.ScheduleService.CreateScheduleService(scheduleService);

				_subItemId = null;
				txtSheduleServiceName.Text = txtSheduleServiceHH.Text = txtSheduleServiceMM.Text = string.Empty;
				pScheduleDayInicialize();
			}
			else
				MessageBox.Show(
					string.Format(
						"Неправильные входные данные:\nВведите название службы и время в формате (часы от 0 до 24, минуты от 0 до 59)"));

			this.Enabled = true;
		}

		#endregion

		#region Tab Galleries Actions

		private void chbFotoclubGalleries_CheckedChanged(object sender, EventArgs e)
		{
			this.Enabled = false;

			ComboBoxGalleriesInicialize();

			this.Enabled = true;
		}

		private void chbImageGalleries_CheckedChanged(object sender, EventArgs e)
		{
			this.Enabled = false;

			ComboBoxGalleriesInicialize();

			this.Enabled = true;
		}

		private void btnAddGallery_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			_id = null;

			pEditGallery.Visible = true;
			txtGalleryName.Text = string.Empty;
			chbIsFotoclubGallery.Checked = chbIsImagesGallery.Checked = false;

			this.Enabled = true;
		}

		private void btnUpdateGallery_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var gallery = (cbGalleries.SelectedItem as GalleryData);
			if (gallery != null)
			{
				_id = gallery.GalleryId;

				pEditGallery.Visible = true;
				txtGalleryName.Text = gallery.Name;
				chbIsFotoclubGallery.Checked = gallery.IsFotoclub;
				chbIsImagesGallery.Checked = gallery.IsImagesGallery;
			}

			this.Enabled = true;
		}

		private void btnDeleteGallery_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var gallery = (cbGalleries.SelectedItem as GalleryData);
			if (gallery != null)
			{
				var result = MessageBox.Show(
					string.Format("Вы уверены что хотите удалить галерею {0} и все её изображения:", gallery.Name),
					string.Format("Удаление галереи"),
					MessageBoxButtons.YesNo,
					MessageBoxIcon.Question);

				if (result == DialogResult.Yes)
				{
					var images = AppContext.ServiceFactory.GalleriesService.GetGalleryImagesByGalleryId(gallery.GalleryId);

					var status = true;

					if (images != null && images.Any())
					{
						InicializeProgressBar(pbDeleteGallery, images.Count());

						foreach (var image in images)
						{
							var delRes = _galleryManager.DeleteImage(image.ImageId);
							if (delRes)
								pbDeleteGallery.PerformStep();
							else
							{
								MessageBox.Show(string.Format("При удалении галереи возникли ошибки!"));
								status = false;
								break;
							}
						}
					}

					if (status)
						AppContext.ServiceFactory.GalleriesService.DeleteGallery(gallery.GalleryId);

					pEditGallery.Visible = false;
					pGalleryImages.Visible = false;
					pbDeleteGallery.Visible = false;
					ComboBoxGalleriesInicialize();
				}
			}

			this.Enabled = true;
		}

		private void btnGallerySave_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			if (string.IsNullOrWhiteSpace(txtGalleryName.Text) || (!chbIsFotoclubGallery.Checked && !chbIsImagesGallery.Checked))
				MessageBox.Show(string.Format("Поле 'Название галереи' должно быть заполнено\nДолжен быть выбран тип галлереи"));
			else
			{
				var entity = new GalleryData
				{
					GalleryId = _id.GetValueOrDefault(),
					Name = txtGalleryName.Text,
					IsFotoclub = chbIsFotoclubGallery.Checked,
					IsImagesGallery = chbIsImagesGallery.Checked
				};

				if (_id.HasValue)
					AppContext.ServiceFactory.GalleriesService.UpdateGallery(entity);
				else
					AppContext.ServiceFactory.GalleriesService.CreateGallery(entity);

				_id = null;
				pEditGallery.Visible = false;
				ComboBoxGalleriesInicialize();
			}

			this.Enabled = true;
		}

		private void btnGalleryImages_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var gallery = cbGalleries.SelectedItem as GalleryData;
			if (gallery != null)
			{
				pGalleryImages.Visible = true;
				pEditGalleryImage.Visible = false;
				ComboBoxGalleryImagesInicialize(gallery.GalleryId);
				_id = gallery.GalleryId;
			}

			this.Enabled = true;
		}

		private void btnEditGalleryImage_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var image = cbGalleryImages.SelectedItem as ImageData;
			if (image != null)
			{
				pEditGalleryImage.Visible = true;
				_isInicializeCheckBox = true;
				chbIsDefaultGalleryImage.Checked = image.IsDefault;
				_isInicializeCheckBox = false;
				_subItemId = image.ImageId;
			}

			this.Enabled = true;
		}

		private void chbIsDefaultGalleryImage_CheckedChanged(object sender, EventArgs e)
		{
			if (_isInicializeCheckBox) return;

			this.Enabled = false;

			AppContext.ServiceFactory.GalleriesService.UpdateGalleryDefaultImage(_subItemId.GetValueOrDefault(), chbIsDefaultGalleryImage.Checked);

			pEditGalleryImage.Visible = false;
			ComboBoxGalleryImagesInicialize(_id.GetValueOrDefault());
			_subItemId = null;

			this.Enabled = true;
		}

		private void btnDeleteImage_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var result = _galleryManager.DeleteImage(_subItemId.GetValueOrDefault());
			MessageBox.Show(result
				? string.Format("Изображение успешно удалено!")
				: string.Format("При удалении изображения возникли ошибки!"));
			pEditGalleryImage.Visible = false;
			ComboBoxGalleryImagesInicialize(_id.GetValueOrDefault());
			_subItemId = null;

			this.Enabled = true;
		}

		private void btnAddGalleryImages_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			pEditGalleryImage.Visible = false;

			var openFolderDialog = new FolderBrowserDialog();
			if (openFolderDialog.ShowDialog() == DialogResult.OK)
			{
				var folderPath = openFolderDialog.SelectedPath;

				var smallImagesFolderPath = Path.Combine(folderPath, AppConfig.SmallImagesFolderName);
				var bigImagesFolderPath = Path.Combine(folderPath, AppConfig.BigImagesFolderName);

				var exceptions = _galleryManager.CheckUploadingImages(smallImagesFolderPath, bigImagesFolderPath);

				if (string.IsNullOrWhiteSpace(exceptions))
				{
					var imageItems = (_galleryManager.GetValidImageItems(smallImagesFolderPath, bigImagesFolderPath)
						?? new List<ImageItem>()).ToList();
					var images = new List<ImageItem>();
					(SortFilePathes(imageItems.Select(ii => ii.BigImageFilePath)) ?? new List<string>())
						.ToList()
						.ForEach(n =>
						{
							var item = imageItems.FirstOrDefault(ii => ii.BigImageFilePath.Equals(n, StringComparison.Ordinal));
							if (item != null)
								images.Add(item);
						});
					imageItems = images;

					if (imageItems.Any())
					{
						InicializeProgressBar(pbAddedImagesToGallery, imageItems.Count());

						foreach (var f in imageItems)
						{
							var result = _galleryManager.SaveImage(f.SmallImageFilePath, f.BigImageFilePath, _id.GetValueOrDefault());
							if (result)
								pbAddedImagesToGallery.PerformStep();
							else
							{
								MessageBox.Show(string.Format("При загрузке изображений возникла ошибка!"));
								break;
							}
						}

						pbAddedImagesToGallery.Visible = false;
						ComboBoxGalleryImagesInicialize(_id.GetValueOrDefault());
					}
				}
				else
					MessageBox.Show(exceptions);
			}

			this.Enabled = true;
		}

		#endregion

		#region Tab Images Manager Actions

		private void btnFolderWithImages_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var openFolderDialog = new FolderBrowserDialog();
			if (openFolderDialog.ShowDialog() == DialogResult.OK)
				txtFolderPathWithImages.Text = openFolderDialog.SelectedPath;

			this.Enabled = true;
		}

		private void btnResultImagesFolder_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			var openFolderDialog = new FolderBrowserDialog();
			if (openFolderDialog.ShowDialog() == DialogResult.OK)
				txtResultImagesFolder.Text = openFolderDialog.SelectedPath;

			this.Enabled = true;
		}

		private void btnStartManagedImages_Click(object sender, EventArgs e)
		{
			this.Enabled = false;

			if (string.IsNullOrWhiteSpace(txtFolderPathWithImages.Text)
				|| string.IsNullOrWhiteSpace(txtResultImagesFolder.Text)
				|| txtFolderPathWithImages.Text.Equals(txtResultImagesFolder.Text))
			{
				MessageBox.Show(string.Format("Необходимо выбрать обе папки (не могут быть одинаковыми) для обработки изображений!"));
				this.Enabled = true;
			}
			else
			{
				var images = (_directoryManager.GetImageFilePathesFromDirectory(txtFolderPathWithImages.Text)
					?? new List<string>()).ToList();
				images = (SortFilePathes(images) ?? new List<string>()).ToList();

				if (images.Any())
				{
					var newBigImagesDirectory = _directoryManager.CreateNewFolderInDirectory(
						txtResultImagesFolder.Text,
						AppConfig.BigImagesFolderName);
					var newSmallImagesDirectory = _directoryManager.CreateNewFolderInDirectory(
						txtResultImagesFolder.Text,
						AppConfig.SmallImagesFolderName);

					pManagedImagesProgress.Visible = true;
					InicializeProgressBar(pbManagedImages, images.Count() * 2);

					var newImageName = 0;
					foreach (var image in images)
					{
						var imageExt = _fileManager.GetFileExtension(image);
						string newBigImagePath;
						string newSmallImagePath;
						do
						{
							newImageName++;
							newBigImagePath = Path.Combine(
							newBigImagesDirectory,
							string.Concat(newImageName.ToString(CultureInfo.InvariantCulture), imageExt));
							newSmallImagePath = Path.Combine(
								newSmallImagesDirectory,
								string.Concat(newImageName.ToString(CultureInfo.InvariantCulture), imageExt));
						} while (File.Exists(newBigImagePath)
							&& File.Exists(newSmallImagePath));

						_imageManager.ResizeImage(image, newBigImagePath, AppConfig.BigImageBoundWidth, AppConfig.BigImageBoundHeight, false);
						pbManagedImages.PerformStep();

						_imageManager.ResizeImage(image, newSmallImagePath, AppConfig.SmallImageBoundWidth, AppConfig.SmallImageBoundHeight, false);
						pbManagedImages.PerformStep();
					}

					pManagedImagesProgress.Visible = false;
				}
			}

			this.Enabled = true;
		}

		#endregion
	}
}
